﻿using System;

namespace Mockery.Core
{
    

    /// <summary>
    /// This class is responsible for allowing the user to create new mocks and stubs quickly.
    /// </summary>
    public class Arranger : IArranger
    {
        private readonly IArrangement _arrangement;

        /// <summary>
        /// This ctor is internal because it is ultimately only called internally by Mockery, its unit
        /// tests and not by the external user
        /// </summary>
        /// <param name="arrangement">the rhino repository</param>
        public Arranger(IArrangement arrangement)
        {
            if( arrangement == null) throw new ArgumentNullException("arrangement");

            _arrangement = arrangement;
        }

        /// <summary>
        /// Provides the ability to retrieve a registered mock or stub and perform expectations on it
        /// </summary>
        /// <typeparam name="TType">previously registered mock or stub</typeparam>
        /// <param name="actionItem">work delegate</param>
        /// <returns>this instance to support fluent interface</returns>
        public Arranger ExpectOn<TType>(Action<TType> actionItem )
        {
            actionItem(_arrangement.GetMockedType<TType>());
            return this;
        }

        /// <summary>
        /// Allows the adding of a strict mock as defined by Rhino
        /// </summary>
        /// <typeparam name="TType">Type being created as a mock</typeparam>
        /// <returns>the Mocks instance for Fluent style chaining</returns>
        public Arranger AddStrictMock<TType>()
        {
            _arrangement.AddStrictMock<TType>();
            return this;
        }

        /// <summary>
        /// Allows adding of a dynamic mock as defined by Rhino
        /// </summary>
        /// <typeparam name="TType">Type being created as a dynamic mock</typeparam>
        /// <returns>Mocks instance for Fluent-style chaining</returns>
        public Arranger AddDynamicMock<TType>() where TType : class
        {
            _arrangement.AddDynamicMock<TType>();
            return this;
        }

        /// <summary>
        /// Allows for adding of a singleton type which typically useful
        /// when using manual mocks
        /// </summary>
        /// <typeparam name="TType">type being added</typeparam>
        /// <param name="value">instance being added</param>
        /// <returns>Mocks instance for Fluent-style chaining</returns>
        public Arranger AddSingletonType<TType>(TType value)
        {
            _arrangement.AddMockedType(value);
            return this;
        }

        /// <summary>
        /// Allows adding of a stub as defined by Rhino
        /// </summary>
        /// <typeparam name="TType">type being stubbed</typeparam>
        /// <returns></returns>
        public Arranger AddStub<TType>()
        {
            _arrangement.AddStub<TType>();
            return this;
        }


        /// <summary>
        /// Retrieves an instance of a mock
        /// </summary>
        /// <typeparam name="TValue">value to be retrieved</typeparam>
        /// <returns>mocked instance</returns>
        public TValue GetMockedValue<TValue>()
        {
            return _arrangement.GetMockedType<TValue>();
        }

    }
}
